/*
 *		File: Allocation.h
 *
 */

#ifndef __Allocation__
#define __Allocation__


#include "Common.h"


void* AllocateNonPre(short post) throw(bad_alloc);
void* Allocate(short pre, short post) throw(bad_alloc);
void DeAllocate(void* free, short pre, short post);


struct FragmentQueueHeader : protected QueueHeader
{
	void PutBlock(void* free);

	typedef	void (*MarkRoots)(void);
	void Collect(MarkRoots roots);
	
 protected:

	friend struct Fragment;
	friend struct PreFragment;

	struct Signature
	{
		short all;
		short post;
		
		Signature(short a, short p) : all(a), post(p) { }
		short Pre(void) { return all - post; }
		bool operator == (const Signature& rhs) const { return all == rhs.all && post == rhs.post; }
		long Eff(long indx) { return all * indx + Pre(); }
	};
	
	inline Fragment* First(void) const;

 public:

	long CountWithSignature(const Signature& sig) const;

};


extern FragmentQueueHeader	Fragments;


struct BlockQueueHeader : protected QueueHeader
{
	BlockQueueHeader(void) : QueueHeader() { }
	
	void* TakeBlock(void) throw(BlockQueueHeader*) { void* block = head; if (block) { head = head->next; if (!head) tail = NIL; } else block = NoMore(); return block; }
	void PutBlock(void* free) { ((QueueElement*)free)->next = NIL; QueueHeader::Add(*((QueueElement*)free)); }
	void* NoMore(void) throw(BlockQueueHeader*);

 protected:

	friend struct Fragment;
	friend struct PreFragment;

	void Add(QueueElement& first, QueueElement& last)
		{ last.next = head;
			if (last.next) head = &first;
			else { head = &first; tail = &last; }
		}

};


extern BlockQueueHeader Blocks[4*20]; // dh pre (0, 4, 8, 12) post (0, 2, 4, 6, ... 38)


struct	Fragment : protected QueueElement
{
	Fragment(short po) : sig(po, po), contains((last - zeroth) / po) { }
	Fragment(short po, short all) : sig(po, all), contains((last - zeroth) / all) { }

	bool Find(void* ptr) { return (ptr >= zeroth) && (ptr < last); }
	long Which(void* ptr) { return ((char*)ptr - zeroth) / sig.all; }
	bool Valid(void* ptr) { return ((char*)ptr - zeroth) % sig.all == sig.Pre(); }
	void* Real(void* ptr) { return (void*)((long)ptr - ((char*)ptr - zeroth) % sig.all + sig.Pre()); }
	
	void* operator new (size_t size, size_t chunk) throw(bad_alloc);

	void QueueUp(FragmentQueueHeader& frags, BlockQueueHeader& blocks);

 protected:

	friend struct FragmentQueueHeader;

	typedef FragmentQueueHeader::Signature Signature;
	
	Signature	sig;

	long	contains;
	char* last;
	
	struct StartOfSpace { char s; };
	enum { superfluous = sizeof(StartOfSpace) };
	char	zeroth[superfluous];
	
	QueueElement* QueueUpShallow(QueueElement* first);
	QueueElement* QueueUpShallow(QueueElement* first, QueueElement* last);
	Fragment* Sweep(void);
	void MarkAll(void);
	
	Fragment* Next(void) const { return static_cast<Fragment*>(next); }
	
};

inline Fragment* FragmentQueueHeader::First(void) const { return static_cast<Fragment*>(head); }

struct	PreFragment : Fragment
{
	friend void* Allocate(short ,short) throw(bad_alloc);

 public:

	PreFragment(short pre, short po) : Fragment(po, pre + po) { }

	void QueueUp(FragmentQueueHeader& frags, BlockQueueHeader& blocks);
	short GetPre(void) { return sig.Pre(); }

};

struct MarkableQueueElement : QueueElement
{
	bool Marked(void) const { return reinterpret_cast<marker const*>(this)->mark; }
	void Mark(void) { reinterpret_cast<marker*>(this)->mark = true; }
	
	MarkableQueueElement* operator - (short delta) { return static_cast<MarkableQueueElement*>((void*)((char*)this - delta)); }
	MarkableQueueElement* operator + (short delta) { return static_cast<MarkableQueueElement*>((void*)((char*)this + delta)); }

 private:

	struct marker
	{
		long	egal:31;
		long	mark:1;
	};

};

#endif// __Allocation__
